<?php
namespace app\index\library;

use app\common\model\ClinicAdmin;
use app\common\model\AuthRule;
use app\common\model\Clinic;
use app\common\model\ClinicAuthGroup;
use app\common\model\ClinicConfig;
use app\common\model\ClinicGroup;
use think\Db;
use think\facade\Cache;
use think\facade\Cookie;
use think\facade\Session;
use think\facade\Request;
use think\facade\Url;
use think\Controller;
use think\facade\Env;
use szktor\Random;
use szktor\Tree;
use szktor\ClinicDict; //诊所门店公共字典

class Auth extends Controller
{
    protected $webCfg = ''; //站点配置
    protected $coustomCookiePre = 'clinic_index'; //自己定义cookie前缀
    protected static $instance;

    public function __construct()
    {
        parent::__construct();
    }

    public static function instance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new static();
        }
        return self::$instance;
    }
	
    /**
     * 设置授权文件全局配置参数
     * @param array $arr 全局配置参数的数组
     */
    public function setAuthWebConfig($arr = [])
    {
       $this->webCfg = $arr;
	   $this->webCfg['cookie_pre'] = $this->webCfg['cookie_pre'] . $this->coustomCookiePre;
    }
    /**
     * 检测当前控制器和方法是否匹配传递的数组
     *
     * @param array $arr 需要验证权限的数组
     */
    public function match($arr = [])
    {
        $request = Request::instance();
        $arr = is_array($arr) ? $arr : explode(',', $arr);
        if (!$arr)
        {
            return FALSE;
        }
        // 是否存在
        if (in_array(strtolower($request->action()), $arr) || in_array('*', $arr))
        {
            return TRUE;
        }
        // 没找到匹配
        return FALSE;
    }
    /**
     * 管理人登录
     * @param   string  $username   用户名
     * @param   string  $password   密码
     * @param   boolean  $usePhone  是否使用手机号码登录  (手机号码登录时，不验证登录密码) 
     * @return  boolean
    */
    public function login($username, $password, $usePhone = false)
    {
		//不建议匹配 |a.nickname ，避免姓名重名问题，登录账号与手机在系统中保持唯一
		$map = ['a.user_name|a.user_mobile' => trim($username), 'a.is_del' => '0'];
		if($usePhone)
		{
			$map = ['a.user_mobile' => trim($username), 'a.is_del' => '0'];
		}
		$admin = ClinicAdmin::alias('a')->join('clinic_auth_group b', 'a.clinic_id = b.clinic_id and a.group_id = b.id', 'left')
				->where($map)->field('a.*,b.name as g_name,b.rules as g_rules,b.status as g_status,b.remark as g_remark,b.index_page,b.is_del as g_is_del')
				->find();
        if(!$admin || !isset($admin['id']) || intval($admin['id']) <= 0)
        {
            return ['err' => '1', 'msg' => '账号不存在'];
        }
		$now_time = time();
		$admin = $admin->toArray();
        if(intval($admin['status']) <= 0)
        {
			return ['err' => '2', 'msg' => '账号已禁用'];
        }
		if(!$usePhone) //非手机号码登录，需要验证登录密码
		{
			if($admin['user_pwd'] != ClinicAdmin::encryptPassword($password,$admin['pwd_salt']))
			{
				return ['err' => '3', 'msg' => '登录密码错误'];
			}
		}
        if(!$admin['group_id'])
        {
			return ['err' => '4', 'msg' => '权限配置错误，禁止登录'];
        }
        if(!$admin['g_status'])
        {
			return ['err' => '5', 'msg' => '权限组已被禁用，禁止登录'];
        }
        if(intval($admin['g_is_del']) > 0)
        {
			return ['err' => '6', 'msg' => '权限组已被清除，无法登录'];
        }
		//诊所信息
		$clinicInfo = Clinic::getClinicInfo($admin['clinic_id']);
		if(!isset($clinicInfo['id']) || intval($clinicInfo['id']) <= 0)
		{
			return ['err' => '7', 'msg' => '对不起，账号无效，无法登录'];
		}
		if(isset($clinicInfo['mall_id']) && intval($clinicInfo['mall_id']) > 0)
		{
			$zdInfo = Clinic::getClinicInfo($clinicInfo['mall_id']); //获得总店信息
			if(!isset($zdInfo['id']) || intval($zdInfo['id']) <= 0)
			{
				return ['err' => '8', 'msg' => '对不起，总店信息无效，无法登录'];
			}
			if(isset($zdInfo['except_time']) && intval($zdInfo['except_time']) > 0)
			{
				if($now_time > $zdInfo['except_time'])
				{
					return ['err' => '9', 'msg' => '系统软件服务已到期，无法登录'];
				}
			}
		}else{
			if(isset($clinicInfo['except_time']) && intval($clinicInfo['except_time']) > 0)
			{
				if($now_time > $clinicInfo['except_time'])
				{
					return ['err' => '10', 'msg' => '系统软件服务已到期，无法登录'];
				}
			}
		}
		if(isset($clinicInfo['status']) && intval($clinicInfo['status']) <= 0)
		{
			return ['err' => '11', 'msg' => '对不起，诊所已停业，无法登录'];
		}
		$r1 = $this->setLogined($admin['id'],$admin['user_pwd']);
		if(!$r1)
		{
			return ['err' => '12', 'msg' => '登录失败，请重试'];
		}
		$r2 = ClinicAdmin::where(['id' => $admin['id']])->update([
			'login_number' => intval($admin['login_number']+1), //累计登录次数
			'last_login_time' => $now_time, //最后登录时间
		]);
        return ['err' => '0', 'msg' => '登录成功，请稍候...'];
    }
    /**
     * 执行登录 或 注册 新账户
     * @param   string  $phone   手机号码
	 * @param   string  $mallCode  总店编号，如果不为空：注册时将注册到此总店下
    */
    public function loginAndRegister($phone = '', $mallCode = '')
    {
		if(!$phone)
		{
			return ['err' => '1', 'msg' => '对不起，手机号码不能为空'];
		}
		$admin = ClinicAdmin::where(['user_mobile' => trim($phone), 'is_del' => '0'])->find();
		if(!$admin || !isset($admin['id']) || intval($admin['id']) <= 0)
		{
			//创建一个新商家、账号
			$now_time = time();
			ClinicAdmin::beginTrans();
		    try
		    {
				//总店信息--验证总店编码是否有效
				$mallInfo = Clinic::verifyShopCode($mallCode,true);
				
				if($mallInfo) //有总店时的 注册信息
				{
					$longName = !$mallInfo['short_name'] ? '我的' : trim($mallInfo['short_name']);
					$regInfo = [
						'mall_id' => $mallInfo['id'], //总店ID,大于零不是总店,0表示为是总店
						'long_name' => $longName . '新分店', //店长名称
						'short_name' => '新分店', //店短名称
					];
				}else{ //无总店时的注册信息
					$regInfo = [
						'mall_id' => '0', //总店ID,大于零不是总店,0表示为是总店
						'long_name' => '我的新总店', //店长名称
						'short_name' => '新总店', //店短名称
					];
				}
				unset($mallInfo);
				
				//取得默认注册的组
				$regClinicGroup = ClinicGroup::getGroupInfo($this->webCfg['reg_default_groupid']);
				if(!isset($regClinicGroup['id']) || intval($regClinicGroup['id']) <= 0)
				{
					return ['err' => '2', 'msg' => '系统暂时关闭注册，请稍候再试'];
				}
				
				//新注册的商家 过期时间
				$exceptTimeStr = empty($regClinicGroup['except_str']) ? '0' : strtotime($regClinicGroup['except_str'],$now_time);
				//生成8位 数字+字母 唯一门店编号
				$shopCode = strtoupper(Clinic::buildUniqueFieldsVal(8,'shop_code'));
				//1.创建一个诊所
				$clinicId = Clinic::insertGetId([
				    'mall_id' => $regInfo['mall_id'], //总店ID,大于零不是总店,0表示为是总店
				    'group_id' => $regClinicGroup['id'], //商家套餐分组ID,clinic_group的id
				    'long_name' => $regInfo['long_name'], //店长名称
				    'short_name' => $regInfo['short_name'], //店短名称
				    'shop_code' => $shopCode, //门店编码/编号
				    'user_mobile' => $phone, //联系人手机号码
				    'create_time' => $now_time, //创建时间
				    'except_time' => $exceptTimeStr, //过期时间
				]);
				//2.创建一个诊所门店系统管理员角色分组
				$clinicAuthGroupId = ClinicAuthGroup::insertGetId([
				    'clinic_id' => $clinicId, //诊所门店表的id
				    'name' => '超级管理', //组名
				    'rules' => '*', //规则ID
				    'create_time' => $now_time, //创建时间
				    'remark' => '系统自动创建', //角色组操作信息备注
				    'index_page' => '/index/home/index', //工作台首页
				    'is_supper_admin' => '1', //是否超级管理员组1.是,0否
				]);	
				//3.创建一个管理员
				$userName = ClinicAdmin::buildUniqueFieldsVal(5,'user_name'); //生成10位 数字+字母 登录账号
				$pwdStr = Random::numeric(8); //创建随机8位数字密码
				$pwdSalt = Random::numeric(5); //创建随机5位密码域
				$md5Pwd = ClinicAdmin::encryptPassword($pwdStr,$pwdSalt);
				$adminId = ClinicAdmin::insertGetId([
				    'clinic_id' => $clinicId, //诊所门店表的id
				    'group_id' => $clinicAuthGroupId, //权限级id
				    'user_name' => $userName, //名称
				    'user_mobile' => $phone, //手机号
				    'user_pwd' => $md5Pwd, //密码
					'pwd_salt' => $pwdSalt, //密码域
				    'nickname' => '超级管理员', //用户姓名
				    'create_time' => $now_time, //创建时间
				    'is_supper_admin' => '1', //是否超级管理员1.是,0否
				]);
				//4.创建一个诊所配置信息
				$clinicConfigId = ClinicConfig::insertGetId([
				    'clinic_id' => $clinicId, //诊所门店表的id
				    'create_time' => $now_time, //创建时间
				]);
				//5.运行一些sql文件语句
				$sqlFile = Env::get('app_path').'index'.DS.'library'.DS.'init_clinic.sql';
				$sqlBody = _readFileContent($sqlFile);
				if($sqlBody)
				{
					//sql文件内变量 替换
					$sqlBody = str_replace('CLINICID',$clinicId,$sqlBody); //诊所ID
					$sqlBody = str_replace('ADMINID',$adminId,$sqlBody); //管理员ID
					$sqlBody = str_replace('ADMINGPID',$clinicAuthGroupId,$sqlBody); //管理员组ID
					$sqlArr = explode(';',$sqlBody);
					if(count($sqlArr))
					{
						foreach($sqlArr as $k => $v){
							$v = trim($v);
							if(!$v) continue; //为空不执行
							if(substr($v,0,2) == '--') continue; //注释不执行
							$sqlRes = ClinicAdmin::execute($v);
						}
					}
					unset($sqlFile,$sqlBody,$sqlArr);
				}
				unset($regInfo,$regClinicGroup);
		    	ClinicAdmin::commitTrans();
				//6.发送短信通知，密码
				$body = '恭喜您已成功注册账号:'.$userName.'或您的手机号，登录密码:' . $pwdStr . '，请妥善保管，切勿泄漏。';
				_sendSMSMessage($phone, $body);
				//7.直接登录
				return $this->login($phone,'',true);
		    }catch (\think\Exception $e){ // use think\Exception;
			    ClinicAdmin::rollbackTrans();
		        return ['err' => 2, 'msg' => '系统错误：' . $e->getMessage()];
		    }
		}else{
			//已存在，直接登录
			return $this->login($phone,'',true);
		}
    }
    /*
    * 获取当前登录信息
    */
    public function getAdminInfo()
    {
       $ckArr = $this->getCookieMemArr();
       if(!$ckArr) return false;
       $uinfo = ClinicAdmin::getAdminLoginInfo($ckArr['id'],$ckArr['pwd']);
       return $uinfo;
    }
    /*
    * 获取当前登录 return ['id' => '1', 'pwd' => 'dsgdsg'];
    */
    public function getCookieMemArr()
    {
		$mid = (int)Session::get($this->webCfg['cookie_pre'] . 'member_id');
		$pwd = trim(Session::get($this->webCfg['cookie_pre'] . 'member_pwd'));
		if($mid <= 0) $mid = (int)Cookie::get($this->webCfg['cookie_pre'] . 'member_id');
		if(!$pwd) $pwd = trim(Cookie::get($this->webCfg['cookie_pre'] . 'member_pwd'));
		if((int)$mid <= 0 || !$pwd) return false;
		return ['id' => $mid, 'pwd' => $pwd];
    }
	
    /**
     * 设置一个用户登录
     */
    public function setLogined($mid = 0, $pwd = '')
    {
		if(!$mid || !$pwd) return false;
		Cookie::set($this->webCfg['cookie_pre'] . 'member_id', $mid);
		Cookie::set($this->webCfg['cookie_pre'] . 'member_pwd', $pwd);
		Session::set($this->webCfg['cookie_pre'] . 'member_id', $mid);
		Session::set($this->webCfg['cookie_pre'] . 'member_pwd', $pwd);
		return true;
    }
    /**
     * 注销登录
     */
    public function logout()
    {
		Cookie::set($this->webCfg['cookie_pre'] . 'member_id', '0');
		Cookie::set($this->webCfg['cookie_pre'] . 'member_pwd', '');
		Session::set($this->webCfg['cookie_pre'] . 'member_id', '0');
		Session::set($this->webCfg['cookie_pre'] . 'member_pwd', '');
		Cookie::delete($this->webCfg['cookie_pre'] . 'member_id');
		Cookie::delete($this->webCfg['cookie_pre'] . 'member_pwd');
		Session::delete($this->webCfg['cookie_pre'] . 'member_id');
		Session::delete($this->webCfg['cookie_pre'] . 'member_pwd');
		Cookie::clear();
		Session::destroy();
		return true;
    }
	
    /*
    * 当前的URL 权限验证
    */
    public function ruleCheck($_url = '',$group = '')
    {
    	if(!$_url || !$group) return false;
    	$checkRes = isset($group['rules_check_res']) ? $group['rules_check_res'] : ['-100'];
    	if(!$checkRes)
    	{
    		return true;
    	}
    	if($_url == $group['index_page']) //工作台页面
		{
			return true;
		}
		$_idArr = array_unique($checkRes);
		$map = [['id','IN',implode(',',$_idArr)],['status','=','1']];   
		$list = AuthRule::where($map)->order('sort desc')->field('id,url')->select();
		if(!$list || count($list) <= 0)
		{
			return false;
		}
		$list = $list->toArray();
		$_url = strtolower($_url);
		$res = false;
		foreach($list as $key => $val)
		{
			if(strpos(trim(strtolower($val['url'])),';') > 0)
			{
				$_tmpArr = explode(';',trim(strtolower($val['url'])));
				if(in_array($_url,$_tmpArr))
				{
					$res = true;
					break;
				}
			}else{
				if(trim(strtolower($val['url'])) == strtolower($_url))
				{
					$res = true;
					break;
				}
			}
		}
		return $res;
    }
    /*
    * 当前管理人员的菜单
    */
    public function getAdminMenu($admin = [],$clinic = [])
    {
		if(!isset($admin['g_rules']) || !isset($clinic['g_rules'])) return [];
		$cacheName = md5('cms_index_adminmenu_list_' . $clinic['id'] . '_' . $admin['id'] . $clinic['g_rules'] . '_' . $admin['g_rules']);
        $arrList = Cache::get($cacheName);
		if($arrList)
		{
			return json_decode($arrList,true);
		}
		$map = [
			['module_type','=','index_menu'], //模块属于 前台
			['type','=','menu'], //类型为菜单的
			['status','=','1'], //已启用的
		];
		$arr = AuthRule::where($map)->order('sort desc')->field('id,pid,title,url,icon')->select();
		if(count($arr) <= 0) return [];
		$arr = $arr->toArray();
		if(isset($admin['index_page']) && $admin['index_page'])
		{
		  $workPageArr = ClinicDict::getWorkspacePageList();
		  foreach ($arr as $k => &$v){
		  	$v['url'] = Url::build(trim($v['url']));
		  	if(count($workPageArr))
		  	{
		  		foreach ($workPageArr as $kb => $vb) {
		  			if(strtolower($v['url']) == strtolower($vb['url']))
				    {
				       $v['url'] = Url::build(trim($admin['index_page']));
				    }
		  		}
		  	}
		  }
		}
		//管理员菜单权限
		//$adminRules = _getCurrAdminRules($admin, $clinic);
		$adminRules = isset($admin['rules_check_res']) ? $admin['rules_check_res'] : ['-100'];
		unset($admin,$clinic);
		$tree = Tree::instance();
		$tree->init($arr);
		$treeArr = $tree->getIndexMenuTreeArray(0,'',$adminRules);
		if(count($treeArr) <= 0) return [];
		//保存一个月
		Cache::set($cacheName, json_encode($treeArr,JSON_UNESCAPED_UNICODE),['expire' => 86400*30]);
		return $treeArr;
    }
    /*
    * 当前管理人员的所有节点 url
    */
    public function getAdminAllRulesList($admin = [])
    {
    	if(!isset($admin['g_rules'])) return [];
    	$adminRules = isset($admin['rules_check_res']) ? $admin['rules_check_res'] : ['-100'];
        $cacheName = md5('cms_index_adminrules_list_' . $admin['id']);
		$arrList = Cache::get($cacheName);
		if($arrList)
		{
			return json_decode($arrList,true);
		}
		$map = [
			['module_type','=','index_menu'], //模块属于 前台
			['status','=','1'], //已启用的
		];
		if($adminRules)
		{
			$map[] = ['id','IN',implode(',',$adminRules)];
		}
		$arr = AuthRule::where($map)->order('sort desc')->field('id,pid,title,url,icon')->select();
		if(count($arr) <= 0) return [];
		$arr = $arr->toArray();
		//保存一个月
		Cache::set($cacheName, json_encode($arr,JSON_UNESCAPED_UNICODE),['expire' => 86400*30]);
		return $arr;
    }

}
